import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.rmi.RemoteException;
import java.rmi.server.UnicastRemoteObject;
import java.sql.SQLException;
import java.util.ArrayList;
import Database.Event;
import Database.DatabaseFactory;
import Database.MySqlConnection;
import Database.Reservation;


public class BookingServiceImpl extends UnicastRemoteObject implements BookingService {
	
	private DatabaseFactory db = null;
	private MySqlConnection mysql_con = null;
	private ArrayList<ClientInterface> managerList = null;
	
	public BookingServiceImpl() throws RemoteException {
		super();
		this.managerList = new ArrayList<ClientInterface>();
	}
	private DatabaseFactory getLink(){
		DatabaseFactory db = null;
		//obtain and establish connection to the database
		mysql_con = new MySqlConnection();
		//obtain and establish connection to the database
		try {
			db = new DatabaseFactory(mysql_con.getConnection());
		} catch (SQLException e) {
			e.printStackTrace();
		}
		return db;
	}
	private void tearDownLink(){
		this.mysql_con.tearDown();
		this.db = null;
		this.mysql_con = null;
	}
	
	/*
	 * (non-Javadoc)
	 * @see BookingService#add(java.lang.String, int)
	 */
	public synchronized String add(String description, int total_space) {
		String feedback = "";
		db = getLink();
		Event event= new Event(description, total_space);
		feedback = db.addEvent( event );			
		
		//close connection and resources
		this.tearDownLink();
		return feedback;
	}
	public synchronized String delete(int event_number, int confirmation_number) {
		
		//get new connection
		db = getLink();
		try 
		{
			String notification= db.deleteReservation(confirmation_number);
			sendNotification( notification );
			tearDownLink();
			return "Reservation deleted\n";
		} 
		catch (RemoteException e) 
		{
			// TODO Auto-generated catch block
			e.printStackTrace();
			tearDownLink();
			return "Problem deleting reservation.\n";
		}
					
	}
	
	/*
	 * (non-Javadoc)
	 * @see BookingService#detail(int)
	 */
	public String detail(int event_number) {
		String feedback = "";
		Event event = null;
		db = getLink();
		if((event= (Event)db.getEvent(event_number)) == null) return "Event #" + 
				event_number + " does not Exist!";
		
		tearDownLink();
		db = getLink();
		feedback = db.getReserforEvent(event_number);
		return event.toString() + feedback;
	}
	
	public synchronized String remove(int event_number) {
		db = getLink();
		String feedback = db.deleteEvent(event_number);
		tearDownLink();
		return feedback;
	}
	
	/*
	 * (non-Javadoc)
	 * @see BookingService#reserve(int, int, java.lang.String)
	 */
	public synchronized String reserve(int event_number, int space_amount, String person_name) {
			Event event = null;
			
			//get connection to the database
			db = getLink();
			
			if((event=db.getEvent(event_number))==null) return "Error. The event does not exist";
			tearDownLink();
			if((event.getAVAILABLE_SPACE()<space_amount)) return "Error. The space requested is not available";
			
			db = getLink();
			//make the reservation
			int confirmationNumber= db.addReservation( event, person_name, space_amount);
			
			tearDownLink();
			if( confirmationNumber > 0 )
			{
				try 
				{
					sendNotification("Notification: Reservation has been added.\n" +
							 		 "Event number :"+event_number+"\n"+
							 		 "Space reserved: "+space_amount+"\n"
									);
				} catch (RemoteException e) 
				{
					e.printStackTrace();
					System.out.println("Error. Something wrong sending notification.");
				}
				return "Reservation's confirmation number: "+confirmationNumber+"\n";
			}
			else 
			{
				return "Error. Invalid Reservation number returned..\n";
			}
	}
	
	/*
	 * (non-Javadoc)
	 * @see BookingService#view()
	 */
	public String view() {
		String feedback = ""; 
			db = getLink();
			feedback = db.viewEvents();
			tearDownLink();
		return feedback;
	}
	

	/**
	 * Adds the client object to the list o clients registered to receieve notifications.
	 */
	public void registerForNotifications(ClientInterface client){
		//store the client in the list
		if(!(managerList.contains(client) ) )
			managerList.add(client);
	}
	
	/**
	 * Sends a notification to all of the clients registered to receive them.
	 * @param notification the notification to send.
	 * @throws java.rmi.RemoteException
	 */
	private synchronized void sendNotification(String notification) throws java.rmi.RemoteException{
	
		for(ClientInterface c: this.managerList){
			c.notifyMe(notification);
		}
	}
	
	/**
	 * Checks if the requested event exists in the database.
	 * @param event_number, the number of the requested event.
	 */
	public Boolean eventExists(int event_number){
		
		Boolean answer= false;
		Event event= null;
		
		//get connection
		db = getLink();
		if( ( event= db.getEvent(event_number) ) != null ) answer= true;
		tearDownLink();
		
		return answer;
	}
	
	/**
	 * Checks if the requested reservation exists in the database.
	 * @param confirmation_number, the number of the requested reservation.
	 */
	public Boolean reservationExists(int confirmation_number){
		
		//get new connection
		db = getLink();
		Boolean answer= db.getReservation(confirmation_number);
		tearDownLink();
		
		return answer;
	}
}
